package kGeom;

import blobDetection.*;
import processing.core.*;

public class kIso {
	
	public static float defaultFalloff = 1.5f;
	public static int defaultPlaneIndex = 2;
	public static float defaultThreshold = 2.0f;
	
	public static kPolyline[] isoSnapshotPolylines( kPointCloud pCloud , kRange range , float energy , int resX, int resY){
		return isoSnapshotPolylines(pCloud,range,resX,resY,energy,defaultThreshold,defaultPlaneIndex,defaultFalloff);		
	}
	
	public static PImage isoSnapshot( kPointCloud pCloud , kRange range , float energy , int resX, int resY){
		return isoSnapshot(pCloud,range,resX,resY,energy,defaultThreshold,defaultPlaneIndex,defaultFalloff); 
	}
	
	public static kPolyline[] isoSnapshotPolylines( kPointCloud pCloud, kRange range, int resX, int resY, float energy, float threshold, int planeIndex, float falloff){
		
		kPointCloud cloud = kPointCloud.flipAxis(pCloud, planeIndex);
		cloud.setPtsZ(0.0f);
		
		// start find scale and trans vec
		range = kRange.flipAxis(range, planeIndex);
		float dX = range.deltX();
		float dY = range.deltY();
		kVec trans = range.center();
		trans.z = 0; 
		float scaleX = 1.0f; if (dX>0) {scaleX = ( resX / dX );}
		float scaleY = 1.0f; if (dY>0) {scaleY = ( resY / dY );}
		// end find scale and trans vec
		
		// start transform to px scale
		cloud.translate(kVec.invert(trans));
		cloud.scaleX(scaleX);
		cloud.scaleY(scaleY);
		cloud.translate(new kVec(resX/2,resY/2));
		// end transform to px scale
		
		PImage img = imageFrom2dPointCloud(cloud,resX,resY,energy,falloff);
		kPolyline[] edges = imageEdgeDetection(img,threshold);
		
		// start transform to unit scale
		// TODO: fix up right
		for (int n=0 ; n<edges.length ; n++)
		{
			edges[n].translate(new kVec(-resX/2,-resY/2));
			edges[n].scaleY((1/scaleY));
			edges[n].scaleX((1/scaleX));
			edges[n].translate(trans);
			edges[n].flipAxis(-planeIndex);
		}
		// end transform to unit scale
		return edges;
	}
	
	public static PImage isoSnapshot(kPointCloud pCloud, kRange range, int resX, int resY, float energy, float threshold, int planeIndex, float falloff){
		kPointCloud cloud = kPointCloud.flipAxis(pCloud, planeIndex);
		cloud.setPtsZ(0.0f);
		
		// start find scale and trans vec
		range = kRange.flipAxis(range, planeIndex);
		float dX = range.deltX();
		float dY = range.deltY();
		kVec trans = range.center();
		trans.z = 0;
		float scaleX = 1.0f; if (dX>0) {scaleX = ( resX / dX );}
		float scaleY = 1.0f; if (dY>0) {scaleY = ( resY / dY );}
		// end find scale and trans vec
		
		// start transform to px scale
		cloud.translate(kVec.invert(trans));
		cloud.scaleX(scaleX);
		cloud.scaleY(scaleY);
		cloud.translate(new kVec(resX/2,resY/2));
		// end transform to px scale
		

		PImage img = imageFrom2dPointCloud(cloud,resX,resY,energy,falloff);
		return img;
	}
	

	
	
	
	

	/**
	 * point cloud is projected upon xy plane, and measured in terms of 1px = 1unit
	 * should be scaled accordingly
	 * 
	 * @param cloud
		a pcloud to take iso snapshot of
	 * @param resolution
		resolution of resulting image
	 * @param energy
		energy output of each point
	 * @param falloff
		1/(distance^falloff)
	 * @return
	 */
	private static PImage imageFrom2dPointCloud(kPointCloud cloud, int resolutionX, int resolutionY, float energy, float falloff) {
		PImage img = new PImage(resolutionX,resolutionY);
		PApplet pA = new PApplet();
		for (int u=0 ; u<resolutionX ; u++)
		{
			for (int v=0 ; v<resolutionY ; v++)
			{
				kVec imgPt = new kVec(u,v);
				float val = 0;
				for (int n=0 ; n<cloud.count() ; n++)
				{
					float dist = imgPt.distance(cloud.getAt(n));
					val+= (1/Math.pow(dist, falloff))*energy;
					//if (dist<2.0) {System.out.println(dist);}
				}
				if (val > 255){val=255;}
				int c = pA.color(val);
				//System.out.println("setat("+u+","+v+","+c+")  "+val);
				img.set(u,v,c);
			}
		}
		return img;
	}
	
	
	
	/**
	 * edges are found within an input image, and returned as an array of kPolylines
	 * kPolylines are scaled to the image with 1px = 1unit
	 * 
	 * @param img 
 	 *		the image to scan
	 * @param threshold
	 * 		edge detection threshold
	 * @return
	 */
	private static kPolyline[] imageEdgeDetection( PImage img , float threshold ){
		
		BlobDetection theBlobDetection = new BlobDetection(img.width, img.height);
		theBlobDetection.setPosDiscrimination(false);
		theBlobDetection.setThreshold(threshold);
		theBlobDetection.computeBlobs(img.pixels);

		Blob b;
		EdgeVertex eA,eB;
		kPolyline[] ret = new kPolyline[theBlobDetection.getBlobNb()];
		//System.out.println("blobcount "+theBlobDetection.getBlobNb());
		for (int n=0 ; n<theBlobDetection.getBlobNb() ; n++)
		{
			ret[n] = new kPolyline();
			b=theBlobDetection.getBlob(n);
			if (b!=null)
			{
				for (int m=0;m<b.getEdgeNb();m++)
				{
					eA = b.getEdgeVertexA(m);
					eB = b.getEdgeVertexB(m);
					if (eA !=null && eB !=null){
						kVec vA = new kVec(eA.x*img.width, eA.y*img.height);
						kVec vB = new kVec(eB.x*img.width, eB.y*img.height);
						ret[n].append(vA);
						ret[n].append(vB);
					}
				}

			}

		}
		
		return ret;

	}
	
	
}
